#include "model.h"
#include <jsoncpp/json/json.h>
#include <iostream>
#include <sstream>

namespace nanok {
std::string to_json(const Pod& pod) {
    Json::Value root;
    Json::Value metadata;
    Json::Value spec;
    Json::Value status;
    
    metadata["name"] = pod.metadata.name;
    metadata["namespace"] = pod.metadata.namespace_;
    metadata["resourceVersion"] = pod.metadata.resourceVersion;
    
    Json::Value containers(Json::arrayValue);
    for (const auto& container : pod.spec.containers) {
        Json::Value c;
        c["name"] = container.name;
        c["image"] = container.image;
        c["port"] = container.port;
        containers.append(c);
    }
    spec["containers"] = containers;
    
    status["phase"] = pod.status.phase;
    status["hostIP"] = pod.status.hostIP;
    status["podIP"] = pod.status.podIP;
    status["startTime"] = pod.status.startTime;
    
    root["metadata"] = metadata;
    root["spec"] = spec;
    root["status"] = status;
    
    Json::StreamWriterBuilder builder;
    return Json::writeString(builder, root);
}

bool from_json(const std::string& json, Pod& pod) {
    std::cout << json << "!" << std::endl;
    Json::Value root;
    Json::CharReaderBuilder builder;
    std::istringstream iss(json);
    std::string errs;
    
    if (!Json::parseFromStream(builder, iss, &root, &errs)) {
        return false;
    }
    
    pod.metadata.name = root["metadata"]["name"].asString();
    pod.metadata.namespace_ = root["metadata"]["namespace"].asString();
    pod.metadata.resourceVersion = root["metadata"]["resourceVersion"].asInt64();
    
    pod.spec.containers.clear();
    for (const auto& container : root["spec"]["containers"]) {
        Container c;
        c.name = container["name"].asString();
        c.image = container["image"].asString();
        c.port = container["port"].asInt();
        pod.spec.containers.push_back(c);
    }
    
    pod.status.phase = root["status"]["phase"].asString();
    pod.status.hostIP = root["status"]["hostIP"].asString();
    pod.status.podIP = root["status"]["podIP"].asString();
    pod.status.startTime = root["status"]["startTime"].asString();
    
    return true;
}


std::string to_json(const Task& task) {
    Json::Value root;
    Json::Value metadata;
    Json::Value spec;
    metadata["name"] = task.metadata.name;
    metadata["namespace"] = task.metadata.namespace_;
    metadata["resourceVersion"] = task.metadata.resourceVersion;
    Json::Value containers(Json::arrayValue);
    spec["podName"] = task.spec.podName;
    spec["assignedNode"] = task.spec.assignedNode;
    root["metadata"] = metadata;
    root["spec"] = spec;
    Json::StreamWriterBuilder builder;
    return Json::writeString(builder, root);
}

bool from_json(const std::string& json, Task& task) {
    Json::Value root;
    Json::CharReaderBuilder builder;
    std::istringstream iss(json);
    std::string errs;
    if (!Json::parseFromStream(builder, iss, &root, &errs)) {
        return false;
    }
    task.metadata.name = root["metadata"]["name"].asString();
    task.metadata.namespace_ = root["metadata"]["namespace"].asString();
    task.metadata.resourceVersion = root["metadata"]["resourceVersion"].asInt64();
    task.spec.podName = root["spec"]["podName"].asString();
    task.spec.assignedNode = root["spec"]["assignedNode"].asString();
    return true;
}

std::string to_json(const Node& node) {
    Json::Value root;
    Json::Value metadata;
    Json::Value spec;
    Json::Value status;
    metadata["name"] = node.metadata.name;
    metadata["namespace"] = node.metadata.namespace_;
    metadata["resourceVersion"] = node.metadata.resourceVersion;
    spec["podCIDR"] = node.spec.podCIDR;
    Json::Value capacityJson(Json::objectValue);
    for (const auto& pair : node.status.capacity) {
        capacityJson[pair.first] = pair.second;
    }
    status["capacity"] = capacityJson;
    Json::Value allocatableJson(Json::objectValue);
    for (const auto& pair : node.status.allocatable) {
        allocatableJson[pair.first] = pair.second;
    }
    status["allocatable"] = allocatableJson;
    root["metadata"] = metadata;
    root["spec"] = spec;
    root["status"] = status;
    Json::StreamWriterBuilder builder;
    return Json::writeString(builder, root);
}

bool from_json(const std::string& json, Node& node) {
    Json::Value root;
    Json::CharReaderBuilder builder;
    std::istringstream iss(json);
    std::string errs;
    if (!Json::parseFromStream(builder, iss, &root, &errs)) {
        return false;
    }
    node.metadata.name = root["metadata"]["name"].asString();
    node.metadata.namespace_ = root["metadata"]["namespace"].asString();
    node.metadata.resourceVersion = root["metadata"]["resourceVersion"].asInt64();
    node.spec.podCIDR = root["spec"]["podCIDR"].asString();
    for (const auto& key : root["status"]["capacity"].getMemberNames()) {
        node.status.capacity[key] = root["status"]["capacity"][key].asString();
    }
    for (const auto& key : root["status"]["allocatable"].getMemberNames()) {
        node.status.allocatable[key] = root["status"]["allocatable"][key].asString();
    }
    return true;
}

} // namespace nanok